package main

import "fmt"

func main() {
	//在做函数调用时，slice 按引用传递，array 按值传递
	//声明时指定长度的，是数组
	var array1 [5]int8

	var array2 [5]int16 = [5]int16{1, 2, 3, 4, 5}

	array3 := [5]int16{1, 2} //1，2，0，0，0

	var array4 = [...]int32{0: 1, 4: 5} //1,0,0,0,5
	//var array4 []int32 = [...]int32{0:1, 4:5}不行
	var array4a [5]int32 = [...]int32{0: 1, 4: 5} //可行但是失去使用...的意义了 1,0,0,0,5

	var array5 = [5]int64{0: 6, 1: 5, 2: 4, 3: 3, 4: 2} //6,5,4,3,2
	//var array5 []int64 = [5]int64{0: 6, 1: 5, 2: 4, 3: 3, 4: 2}不行

	var array6 [5]float32 = [5]float32{0: 10.0, 4: 20.0} //10.0,0.0,0.0,0.0,20.0

	//-------------------------------------下面是切片
	//声明一个未指定大小的数组来定义切片
	/*
		s = s[low : high : max] 切片的三个参数的切片截取的意义为
		low 为截取的起始下标（含），
		high 为截取的结束下标（不含 high），
		max 为切片保留的原切片的最大下标（不含 max）；
		即新切片从老切片的 low 下标元素开始，
		len = high - low,
		cap = max - low；
		high 和 max 一旦超出在老切片中越界，就会发生 runtime err，slice out of range。
		另外如果省略第三个参数的时候，第三个参数默认和第二个参数相同，即 len = cap。
	*/
	var array13 []int16                   //未初始化的切片默认nil，长度为0
	var array7 []int32 = []int32{1, 2, 3} //1,2,3
	var array8 []int16 = array2[:]        //0，1，2，3，4
	var array9 []int16 = array2[0:2]      //有效截取范围是endIndex-1，也就是0，1
	var array10 []int16 = array2[3:]      //3，4
	var array11 []int16 = array2[:3]      //0，1，2
	var array15 []int16 = array2[0:2:4]   //1,2 array15长度2个元素，容量4个元素
	fmt.Printf("array2[0:2:4] = %v, array15 = %v \n", array2[0:2:4], array15)
	fmt.Printf("len = %d, cap = %d, slice = %v \n", len(array15), cap(array15), array15)
	//make([]T, length, capacity)
	var array12 []int16 = make([]int16, 5, 5)
	var array14 []int16 = make([]int16, 5)

	//如果想增加切片的容量，我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来
	/*
		append 会让切片和与他相关的切片脱钩，但地址不变
		通过 b:=a 引用的方式，当 cap(b) 小于 len(a)，修改 a[i] 的值并不会改变 b[i] 的值；
		但是如果 cap(b) ≥ len(a) 时，修改 a[i] 的值就会改变 b[i] 的值；
		要想使两个切片同步改变，最好的方式是使用切片指针来实现
		细节看app6a中的代码
	*/
	array13 = append(array13, 1)
	array13 = append(array13, 2)
	array13 = append(array13, 3, 4, 5)
	//array12 与 array13是独立创建的2个变量，所以这里的copy()属于深拷贝
	copy(array12, array13) //把array13的元素逐个拷贝到array12
	/*
		append()操作会扩容容量

		首先判断，如果新申请容量（cap）大于2倍的旧容量（old.cap），最终容量（newcap）就是新申请的容量（cap）。
		否则判断，如果旧切片的长度小于1024，则最终容量(newcap)就是旧容量(old.cap)的两倍，即（newcap=doublecap），
		否则判断，如果旧切片长度大于等于1024，则最终容量（newcap）从旧容量（old.cap）开始循环增加原来的1/4，
			即（newcap=old.cap,for {newcap += newcap/4}）直到最终容量（newcap）大于等于新申请的容量(cap)，即（newcap >= cap）
		如果最终容量（cap）计算值溢出，则最终容量（cap）就是新申请容量（cap）。
		需要注意的是，切片扩容还会根据切片中元素的类型不同而做不同的处理，比如int和string类型的处理方式就不一样。


		参数 cap(申请容量) 是怎么计算的
		申请容量 = (旧容量（old.cap） + 追加元素的长度)，如果`申请容量`是单数则 申请容量 = 申请容量 + 1，再将这个`申请容量`传入扩容的方法进行判断
	*/

	for i := 0; i < len(array1); i++ {
		fmt.Printf("array1[%d] = %d \n", i, array1[i])
	}

	/*
		range遍历中的value，每一个都是单独的地址
	*/
	for key1, value1 := range array2 {
		fmt.Printf("array2[%d] = %d \n", key1, value1)
	}

	fmt.Printf("%d,%d,%d,%f,%d,%d,%d,%d,%d,%d,%d,%d,%d \n", array3[0], array4[0], array5[0], array6[0], array7[0], array4a[0], array8[0], array9[1], array10[0], array11[0], array12[0], array13[0], array15[0])
	fmt.Printf("len(array13) = %d,cap(array13) = %d \n", len(array13), cap(array13))
	fmt.Printf("len(array12) = %d,cap(array12) = %d \n", len(array12), cap(array12))
	for i := 0; i < len(array12); i++ {
		fmt.Printf("array12[%d] = %d \n", i, array12[i])
	}
	fmt.Printf("len(array14) = %d,cap(array14) = %d \n", len(array14), cap(array14))

	for key, value := range "hello" {
		fmt.Printf("字符串[%d] = %c\n", key, value)
	}
	//UTF-8字符集使用range遍历字符串，可以按照字符集的字节规则正常输出人类可读的单个字符
	var chinese string = "中国人"
	for key, value := range chinese {
		fmt.Printf("chinese[%d] = %c,chinese[%d] = 0x%x\n", key, value, key, value)
	}
	for i := 0; i < len(chinese); i++ {
		fmt.Printf("chinese[%d] = %c,chinese[%d] = 0x%x\n", i, chinese[i], i, chinese[i])
	}
}
